package com.yunlongn.common.json.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.yunlongn.common.json.AbstractJsonParser;
import com.yunlongn.common.json.TypeReference;
import com.yunlongn.common.json.config.JsonConfig;
import com.yunlongn.common.json.config.SerializeConfig;
import com.yunlongn.common.json.jackson.factory.AbstractJsonSerializer;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * gson 解析
 * @author Yun
 * @since 20210902
 */
public class GsonParser extends AbstractJsonParser {

    public GsonParser(JsonConfig config) {
        super(config);
    }
    public GsonParser() {
        super(new JsonConfig());
    }
    /**
     * 反序列化对象实体
     */
    private Gson gson;
    /**
     * 存放不同序列化类型的对象单例
     */
    private ConcurrentMap<String, Gson> gsonMap = new ConcurrentHashMap<>();

    @Override
    protected void newJsonParser(JsonConfig jsonConfig) {
        SerializeConfig config = new SerializeConfig();
        GsonBuilder gsonBuilder = new GsonBuilder()
                .registerTypeAdapter(Date.class, new DateTypeAdapter(null))
                .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter(jsonConfig))
//                .registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter(jsonConfig))
                .registerTypeAdapter(Double.class, new DoubleTypeAdapter())
                .registerTypeAdapter(String.class, new StringTypeAdapter(jsonConfig))
                .addDeserializationExclusionStrategy(new GsonExclusionStrategy());
        if (config.isSerializeNulls()) {
            gsonBuilder.serializeNulls();
        }
        this.gson = gsonBuilder.create();
    }

    @Override
    public <T> String toJsonString(T obj, boolean serializeNulls, String pattern) {
        String key = serializeNulls + ":" + pattern;
        Gson gson = gsonMap.get(key);
        if (gson == null) {
            GsonBuilder gsonBuilder = new GsonBuilder()
                    .registerTypeAdapter(Date.class, new DateTypeAdapter(pattern))
                    .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter(pattern))
                    .registerTypeAdapter(Double.class, new DoubleTypeAdapter())
                    .registerTypeAdapter(String.class, new StringTypeAdapter())
                    .addSerializationExclusionStrategy(new GsonExclusionStrategy());
            if (serializeNulls) {
                gsonBuilder.serializeNulls();
            }
            gson = gsonBuilder.create();
            gsonMap.putIfAbsent(key, gson);
        }
        return gson.toJson(obj);
    }

    @Override
    public <T> T fromJson(String jsonStr, Class<T> tClass) {
        return gson.fromJson(jsonStr, tClass);
    }

    @Override
    public <T> T fromJson(InputStream jsonIn, Class<T> tClass) {
        return gson.fromJson(new InputStreamReader(jsonIn), tClass);
    }

    @Override
    public <T> T fromJson(String jsonStr, Type type) {
        return gson.fromJson(jsonStr, type);
    }

    @Override
    public <T> T fromJson(InputStream jsonIn, Type type) {
        return gson.fromJson(new InputStreamReader(jsonIn), type);
    }

    @Override
    public <T> List<T> fromJsonArray(String jsonStr, TypeReference<List<T>> typeReference) {
        return gson.fromJson(jsonStr, typeReference.getType());
    }

    @Override
    public <T> String toJsonString(T obj, boolean serializeNulls, String datePattern, Map<Class<?>, AbstractJsonSerializer<?>> jsonDeserializerMap) {
        return null;
    }
}
